Introducción

Para el modelo de Análisis Discriminante Lineal vamos a utilizar la función LinearDiscriminantAnalysis del paquete sklearn. Para mayor información de la función puede ingresar al siguiente enlace: https://scikit-learn.org/stable/modules/generated/sklearn.discriminant_analysis.LinearDiscriminantAnalysis.html

En cuanto al modelo de Análisis Discriminante Cuadrático vamos a utilizar la función QuadraticDiscriminantAnalysis del paquete sklearn. Para mayor información de la función puede ingresar al siguiente enlace: https://scikit-learn.org/stable/modules/generated/sklearn.discriminant_analysis.QuadraticDiscriminantAnalysis.html

Paquetes a utilizar

import os
import pandas as pd
import numpy  as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis
from sklearn.metrics import confusion_matrix
from pandas import DataFrame
from matplotlib import colors as mcolors
import warnings
warnings.filterwarnings('ignore')

Clase Analisis_Predictivo

from pandas import DataFrame
import seaborn as sns

class Analisis_Predictivo:

    def __init__(self,datos:DataFrame, predecir:str, predictoras = [],
                 modelo = None,train_size = 80,random_state = None):
        '''
        datos: Datos completos y listos para construir un modelo
        
        modelo: Instancia de una Clase de un método de clasificación(KNN,Árboles,SVM,etc).
        Si no especifica un modelo no podrá utilizar el método fit_n_review()
        
        predecir: Nombre de la variable a predecir
        
        predictoras: Lista de los nombres de las variables predictoras.
        Si vacío entonces utiliza todas las variables presentes excepto la variable a predecir.
        
        train_size: Proporción de la tabla de entrenamiento respecto a la original.
        
        random_state: Semilla aleatoria para la división de datos(training-testing).
        '''        
        self.__datos = datos
        self.__predecir = predecir
        self.__predictoras = predictoras
        self.__modelo = modelo
        self.__random_state = random_state
        if modelo != None:
            self.__train_size = train_size
            self._training_testing()
    
    @property
    def datos(self):
        return self.__datos
    
    @property
    def predecir(self):
        return self.__predecir
    
    @property
    def predictoras(self):
        return self.__predictoras
    
    @property
    def modelo(self):
        return self.__modelo
    
    @property
    def random_state(self):
        return self.__random_state
    
    @property
    def train_size(self):
        return self.__train_size
    
    @datos.setter
    def datos(self, datos):
        self.__datos = datos
    
    @predecir.setter
    def predecir(self, predecir):
        self.__predecir = predecir
        
    @predictoras.setter
    def predictoras(self, predictoras):
        self.__predictoras = predictoras
        
    @modelo.setter
    def modelo(self, modelo):
        self.__modelo = modelo
        
    @random_state.setter
    def random_state(self, random_state):
        self.__random_state = random_state
        
    @train_size.setter
    def train_size(self, train_size):
        self.__train_size = train_size
        
    def _training_testing(self):
        if len(self.predictoras) == 0:
            X = self.datos.drop(columns=[self.predecir])
        else:
            X = self.datos[self.predictoras]
            
        y = self.datos[self.predecir].values
        
        train_test = train_test_split(X, y, train_size=self.train_size, 
                                      random_state=self.random_state)
        self.X_train, self.X_test,self.y_train, self.y_test = train_test
        
    def fit_predict(self):
        if(self.modelo != None):
            self.modelo.fit(self.X_train,self.y_train)
            return self.modelo.predict(self.X_test)
        
    def fit_predict_resultados(self, imprimir = True):
        if(self.modelo != None):
            y = self.datos[self.predecir].values
            prediccion = self.fit_predict()
            MC = confusion_matrix(self.y_test, prediccion)
            indices = self.indices_general(MC,list(np.unique(y)))
            if imprimir == True:
                for k in indices:
                    print("\n%s:\n%s"%(k,str(indices[k])))
            
            return indices
    
    def indices_general(self,MC, nombres = None):
        "Método para calcular los índices de calidad de la predicción"
        precision_global = np.sum(MC.diagonal()) / np.sum(MC)
        error_global = 1 - precision_global
        precision_categoria  = pd.DataFrame(MC.diagonal()/np.sum(MC,axis = 1)).T
        if nombres!=None:
            precision_categoria.columns = nombres
        return {"Matriz de Confusión":MC, 
                "Precisión Global":precision_global, 
                "Error Global":error_global, 
                "Precisión por categoría":precision_categoria}
    
    def distribucion_variable_predecir(self):
        "Método para graficar la distribución de la variable a predecir"
        variable_predict = self.predecir
        data = self.datos
        colors = list(dict(**mcolors.CSS4_COLORS))
        df = pd.crosstab(index=data[variable_predict],columns="valor") / data[variable_predict].count()
        fig = plt.figure(figsize=(10,9))
        g = fig.add_subplot(111)
        countv = 0
        titulo = "Distribución de la variable %s" % variable_predict
        for i in range(df.shape[0]):
            g.barh(1,df.iloc[i],left = countv, align='center',color=colors[11+i],label= df.iloc[i].name)
            countv = countv + df.iloc[i]
        vals = g.get_xticks()
        g.set_xlim(0,1)
        g.set_yticklabels("")
        g.set_title(titulo)
        g.set_ylabel(variable_predict)
        g.set_xticklabels(['{:.0%}'.format(x) for x in vals])
        countv = 0 
        for v in df.iloc[:,0]:
            g.text(np.mean([countv,countv+v]) - 0.03, 1 , '{:.1%}'.format(v), color='black', fontweight='bold')
            countv = countv + v
        g.legend(loc='upper center', bbox_to_anchor=(1.08, 1), shadow=True, ncol=1)
        
    def poder_predictivo_categorica(self, var:str):
        "Método para ver la distribución de una variable categórica respecto a la predecir"
        data = self.datos
        variable_predict = self.predecir
        df = pd.crosstab(index= data[var],columns=data[variable_predict])
        df = df.div(df.sum(axis=1),axis=0)
        titulo = "Distribución de la variable %s según la variable %s" % (var,variable_predict)
        g = df.plot(kind='barh',stacked=True,legend = True, figsize = (10,9), \
                    xlim = (0,1),title = titulo, width = 0.8)
        vals = g.get_xticks()
        g.set_xticklabels(['{:.0%}'.format(x) for x in vals])
        g.legend(loc='upper center', bbox_to_anchor=(1.08, 1), shadow=True, ncol=1)
        for bars in g.containers:
            plt.setp(bars, width=.9)
        for i in range(df.shape[0]):
            countv = 0 
            for v in df.iloc[i]:
                g.text(np.mean([countv,countv+v]) - 0.03, i , '{:.1%}'.format(v), color='black', fontweight='bold')
                countv = countv + v
                
                
    def poder_predictivo_numerica(self,var:str):
        "Función para ver la distribución de una variable numérica respecto a la predecir"
        sns.FacetGrid(self.datos, hue=self.predecir, height=6).map(sns.kdeplot, var, shade=True).add_legend()

Análisis Discriminante Lineal

Ejemplo 1

Carga de datos

Se cargan los datos de iris.

datos = pd.read_csv('../datos/iris.csv', delimiter = ';', decimal = ".")
print(datos.shape)
## (150, 5)
print(datos.head())
##    s.largo  s.ancho  p.largo  p.ancho    tipo
## 0      5.1      3.5      1.4      0.2  setosa
## 1      4.9      3.0      1.4      0.2  setosa
## 2      4.7      3.2      1.3      0.2  setosa
## 3      4.6      3.1      1.5      0.2  setosa
## 4      5.0      3.6      1.4      0.2  setosa
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 150 entries, 0 to 149
## Data columns (total 5 columns):
##  #   Column   Non-Null Count  Dtype  
## ---  ------   --------------  -----  
##  0   s.largo  150 non-null    float64
##  1   s.ancho  150 non-null    float64
##  2   p.largo  150 non-null    float64
##  3   p.ancho  150 non-null    float64
##  4   tipo     150 non-null    object 
## dtypes: float64(4), object(1)
## memory usage: 6.0+ KB
## None

Poder Predictivo

Creamos una instancia de la clase Analisis_Predictivo() sin especificar un modelo.

analisis_Iris = Analisis_Predictivo(datos, predecir = "tipo")

Distribución de la variable a predecir.

analisis_Iris.distribucion_variable_predecir()
plt.show()

Poder predictivo.

for var in datos.columns[0:4]:
  if(datos[var].dtype in ['float64', 'int', 'float']):
    analisis_Iris.poder_predictivo_numerica(var)
    plt.show()
  else:
    analisis_Iris.poder_predictivo_categorica(var)
    plt.show()

Predicción

Creamos una instancia de la clase LinearDiscriminantAnalysis.

# Usamos los parámetros por defecto
lda = LinearDiscriminantAnalysis()

Creamos una instancia de la clase Analisis_Predictivo() especificando un modelo predictivo.

analisis_Iris = Analisis_Predictivo(datos, predecir = "tipo", modelo = lda, 
                                    train_size = 0.7, random_state = 0)

Entrena el modelo y realiza la predicción sobre la tabla de testing llamando al método fit_predict().

print("Las predicciones en Testing son: {}".format(analisis_Iris.fit_predict()))
## Las predicciones en Testing son: ['virginica' 'versicolor' 'setosa' 'virginica' 'setosa' 'virginica'
##  'setosa' 'versicolor' 'versicolor' 'versicolor' 'virginica' 'versicolor'
##  'versicolor' 'versicolor' 'versicolor' 'setosa' 'versicolor' 'versicolor'
##  'setosa' 'setosa' 'virginica' 'versicolor' 'setosa' 'setosa' 'virginica'
##  'setosa' 'setosa' 'versicolor' 'versicolor' 'setosa' 'virginica'
##  'versicolor' 'setosa' 'virginica' 'virginica' 'versicolor' 'setosa'
##  'virginica' 'versicolor' 'versicolor' 'virginica' 'setosa' 'virginica'
##  'setosa' 'setosa']

Entrena el modelo y realiza la predicción sobre la tabla de testing, además muestra los principales índices de precisión para medir la calidad del modelo. Esto utilizando el método fit_predict_resultados().

resultados = analisis_Iris.fit_predict_resultados()
## 
## Matriz de Confusión:
## [[16  0  0]
##  [ 0 17  1]
##  [ 0  0 11]]
## 
## Precisión Global:
## 0.9777777777777777
## 
## Error Global:
## 0.022222222222222254
## 
## Precisión por categoría:
##    setosa  versicolor  virginica
## 0     1.0    0.944444        1.0

Predicción con selección de variables

#Instancia de la clase(Modelo)
lda = LinearDiscriminantAnalysis()

analisis_Iris = Analisis_Predictivo(datos, predecir = "tipo", predictoras = ["p.ancho","p.largo"],
                                    modelo = lda, train_size = 0.7, random_state = 0)

#Podemos ver la tabla de training
analisis_Iris.X_train.head()
##      p.ancho  p.largo
## 60       1.0      3.5
## 116      1.8      5.5
## 144      2.5      5.7
## 119      1.5      5.0
## 108      1.8      5.8
#Entrenamos, predecimos y medimos la calidad del modelo generado
resultados = analisis_Iris.fit_predict_resultados()
## 
## Matriz de Confusión:
## [[16  0  0]
##  [ 0 17  1]
##  [ 0  1 10]]
## 
## Precisión Global:
## 0.9555555555555556
## 
## Error Global:
## 0.0444444444444444
## 
## Precisión por categoría:
##    setosa  versicolor  virginica
## 0     1.0    0.944444   0.909091

Ejemplo 2

Carga de datos

Se cargan los datos de Scoring de Crédito.

datos = pd.read_csv('../datos/MuestraCredito5000V2.csv', delimiter = ';', decimal = ".")
print(datos.shape)
## (5000, 6)
print(datos.head())
##    MontoCredito  IngresoNeto  ...  GradoAcademico BuenPagador
## 0         14327            1  ...       Bachiller          Si
## 1        111404            1  ...       Bachiller          Si
## 2         21128            1  ...       Bachiller          Si
## 3         15426            2  ...       Bachiller          Si
## 4         10351            1  ...       Bachiller          Si
## 
## [5 rows x 6 columns]
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 5000 entries, 0 to 4999
## Data columns (total 6 columns):
##  #   Column             Non-Null Count  Dtype 
## ---  ------             --------------  ----- 
##  0   MontoCredito       5000 non-null   int64 
##  1   IngresoNeto        5000 non-null   int64 
##  2   CoefCreditoAvaluo  5000 non-null   int64 
##  3   MontoCuota         5000 non-null   object
##  4   GradoAcademico     5000 non-null   object
##  5   BuenPagador        5000 non-null   object
## dtypes: int64(3), object(3)
## memory usage: 234.5+ KB
## None
Nota: Está tomando erroneamente los datos como numéricos, en este caso se deben convertir las variables categóricas porque en realidad estos numéros son códigos NO es que siempre se deban convertir las variables numéricas a categórica.
# Convierte las variables de object a categórica
datos['IngresoNeto'] = datos['IngresoNeto'].astype('category')
datos['CoefCreditoAvaluo'] = datos['CoefCreditoAvaluo'].astype('category')
datos['MontoCuota'] = datos['MontoCuota'].astype('category')
datos['GradoAcademico'] = datos['GradoAcademico'].astype('category')
# Recodifica las categorías usando números
datos["MontoCuota"] = datos["MontoCuota"].cat.codes
datos["GradoAcademico"] = datos["GradoAcademico"].cat.codes
# Convierte las variables de entero a categórica
datos['MontoCuota'] = datos['MontoCuota'].astype('category')
datos['GradoAcademico'] = datos['GradoAcademico'].astype('category')
print(datos.head())
##    MontoCredito IngresoNeto  ... GradoAcademico BuenPagador
## 0         14327           1  ...              0          Si
## 1        111404           1  ...              0          Si
## 2         21128           1  ...              0          Si
## 3         15426           2  ...              0          Si
## 4         10351           1  ...              0          Si
## 
## [5 rows x 6 columns]
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 5000 entries, 0 to 4999
## Data columns (total 6 columns):
##  #   Column             Non-Null Count  Dtype   
## ---  ------             --------------  -----   
##  0   MontoCredito       5000 non-null   int64   
##  1   IngresoNeto        5000 non-null   category
##  2   CoefCreditoAvaluo  5000 non-null   category
##  3   MontoCuota         5000 non-null   category
##  4   GradoAcademico     5000 non-null   category
##  5   BuenPagador        5000 non-null   object  
## dtypes: category(4), int64(1), object(1)
## memory usage: 98.6+ KB
## None

Poder Predictivo

Configuramos y creamos nuestras instancias.

lda = LinearDiscriminantAnalysis()
analisis_scoring = Analisis_Predictivo(datos, predecir = "BuenPagador", modelo = lda,
                                       train_size = 0.75, random_state = 0)

Balance de las clases en la variable a predecir - Problema desvalanceado.

analisis_scoring.distribucion_variable_predecir()
plt.show()

Poder predictivo.

for var in datos.columns[0:5]:
  if(datos[var].dtype in ['float64', 'int', 'float']):
    analisis_scoring.poder_predictivo_numerica(var)
    plt.show()
  else:
    analisis_scoring.poder_predictivo_categorica(var)
    plt.show()

Predicción

Entrenamos el modelo y medimos la calidad del mismo con la predicción generada con base a la tabla de testing.

resultados = analisis_scoring.fit_predict_resultados()
## 
## Matriz de Confusión:
## [[   9  157]
##  [  19 1065]]
## 
## Precisión Global:
## 0.8592
## 
## Error Global:
## 0.14080000000000004
## 
## Precisión por categoría:
##          No        Si
## 0  0.054217  0.982472

También podemos simplemente guardar los resultados y no imprimir en pantalla.

resultados = analisis_scoring.fit_predict_resultados(imprimir = False)
resultados
## {'Matriz de Confusión': array([[   9,  157],
##        [  19, 1065]]), 'Precisión Global': 0.8592, 'Error Global': 0.14080000000000004, 'Precisión por categoría':          No        Si
## 0  0.054217  0.982472}

Ejemplo 3

Carga de datos

Se cargan los datos de SAHeart.

datos = pd.read_csv('../datos/SAheart.csv',delimiter=';',decimal=".")
print(datos.shape)
## (462, 10)
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 462 entries, 0 to 461
## Data columns (total 10 columns):
##  #   Column     Non-Null Count  Dtype  
## ---  ------     --------------  -----  
##  0   sbp        462 non-null    int64  
##  1   tobacco    462 non-null    float64
##  2   ldl        462 non-null    float64
##  3   adiposity  462 non-null    float64
##  4   famhist    462 non-null    object 
##  5   typea      462 non-null    int64  
##  6   obesity    462 non-null    float64
##  7   alcohol    462 non-null    float64
##  8   age        462 non-null    int64  
##  9   chd        462 non-null    object 
## dtypes: float64(5), int64(3), object(2)
## memory usage: 36.2+ KB
## None
print(datos.head())
##    sbp  tobacco   ldl  adiposity  famhist  typea  obesity  alcohol  age chd
## 0  160    12.00  5.73      23.11  Present     49    25.30    97.20   52  Si
## 1  144     0.01  4.41      28.61   Absent     55    28.87     2.06   63  Si
## 2  118     0.08  3.48      32.28  Present     52    29.14     3.81   46  No
## 3  170     7.50  6.41      38.03  Present     51    31.99    24.26   58  Si
## 4  134    13.60  3.50      27.78  Present     60    25.99    57.34   49  Si
# Convierte las variables de object a categórica
datos['famhist'] = datos['famhist'].astype('category')
# Recodifica las categorías usando números
datos["famhist"] = datos["famhist"].cat.codes
# Convierte las variables de entero a categórica
datos['famhist'] = datos['famhist'].astype('category')
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 462 entries, 0 to 461
## Data columns (total 10 columns):
##  #   Column     Non-Null Count  Dtype   
## ---  ------     --------------  -----   
##  0   sbp        462 non-null    int64   
##  1   tobacco    462 non-null    float64 
##  2   ldl        462 non-null    float64 
##  3   adiposity  462 non-null    float64 
##  4   famhist    462 non-null    category
##  5   typea      462 non-null    int64   
##  6   obesity    462 non-null    float64 
##  7   alcohol    462 non-null    float64 
##  8   age        462 non-null    int64   
##  9   chd        462 non-null    object  
## dtypes: category(1), float64(5), int64(3), object(1)
## memory usage: 33.2+ KB
## None
datos.head()
##    sbp  tobacco   ldl  adiposity famhist  typea  obesity  alcohol  age chd
## 0  160    12.00  5.73      23.11       1     49    25.30    97.20   52  Si
## 1  144     0.01  4.41      28.61       0     55    28.87     2.06   63  Si
## 2  118     0.08  3.48      32.28       1     52    29.14     3.81   46  No
## 3  170     7.50  6.41      38.03       1     51    31.99    24.26   58  Si
## 4  134    13.60  3.50      27.78       1     60    25.99    57.34   49  Si

Poder Predictivo

Configuramos y creamos nuestras instancias.

lda = LinearDiscriminantAnalysis()
analisis_Sheart = Analisis_Predictivo(datos, predecir = "chd", modelo = lda,
                                      train_size = 0.8, random_state = 0)

Equilibrio de la variable a predecir.

analisis_Sheart.distribucion_variable_predecir()
plt.show()

Poder predictivo.

for var in datos.columns[0:9]:
  if(datos[var].dtype in ['float64', 'int', 'float']):
    analisis_Sheart.poder_predictivo_numerica(var)
    plt.show()
  else:
    analisis_Sheart.poder_predictivo_categorica(var)
    plt.show()

Predicción

Entrena, predice y mide la calidad.

resultados = analisis_Sheart.fit_predict_resultados()
## 
## Matriz de Confusión:
## [[52  9]
##  [16 16]]
## 
## Precisión Global:
## 0.7311827956989247
## 
## Error Global:
## 0.26881720430107525
## 
## Precisión por categoría:
##          No   Si
## 0  0.852459  0.5

Análisis Discriminante Cuadrático

Ejemplo 1

Carga de datos

Se cargan los datos de iris.

datos = pd.read_csv('../datos/iris.csv', delimiter = ';', decimal = ".")
print(datos.shape)
## (150, 5)
print(datos.head())
##    s.largo  s.ancho  p.largo  p.ancho    tipo
## 0      5.1      3.5      1.4      0.2  setosa
## 1      4.9      3.0      1.4      0.2  setosa
## 2      4.7      3.2      1.3      0.2  setosa
## 3      4.6      3.1      1.5      0.2  setosa
## 4      5.0      3.6      1.4      0.2  setosa
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 150 entries, 0 to 149
## Data columns (total 5 columns):
##  #   Column   Non-Null Count  Dtype  
## ---  ------   --------------  -----  
##  0   s.largo  150 non-null    float64
##  1   s.ancho  150 non-null    float64
##  2   p.largo  150 non-null    float64
##  3   p.ancho  150 non-null    float64
##  4   tipo     150 non-null    object 
## dtypes: float64(4), object(1)
## memory usage: 6.0+ KB
## None

Poder Predictivo

Creamos una instancia de la clase Analisis_Predictivo() sin especificar un modelo.

analisis_Iris = Analisis_Predictivo(datos, predecir = "tipo")

Distribución de la variable a predecir.

analisis_Iris.distribucion_variable_predecir()
plt.show()

Poder predictivo.

for var in datos.columns[0:4]:
  if(datos[var].dtype in ['float64', 'int', 'float']):
    analisis_Iris.poder_predictivo_numerica(var)
    plt.show()
  else:
    analisis_Iris.poder_predictivo_categorica(var)
    plt.show()

Predicción

Creamos una instancia de la clase QuadraticDiscriminantAnalysis.

# Usamos los parámetros por defecto
qda = QuadraticDiscriminantAnalysis()

Creamos una instancia de la clase Analisis_Predictivo() especificando un modelo predictivo.

analisis_Iris = Analisis_Predictivo(datos, predecir = "tipo", modelo = qda, 
                                    train_size = 0.7, random_state = 0)

Entrena el modelo y realiza la predicción sobre la tabla de testing llamando al método fit_predict().

print("Las predicciones en Testing son: {}".format(analisis_Iris.fit_predict()))
## Las predicciones en Testing son: ['virginica' 'versicolor' 'setosa' 'virginica' 'setosa' 'virginica'
##  'setosa' 'versicolor' 'versicolor' 'versicolor' 'virginica' 'versicolor'
##  'versicolor' 'versicolor' 'versicolor' 'setosa' 'versicolor' 'versicolor'
##  'setosa' 'setosa' 'virginica' 'versicolor' 'setosa' 'setosa' 'virginica'
##  'setosa' 'setosa' 'versicolor' 'versicolor' 'setosa' 'virginica'
##  'versicolor' 'setosa' 'virginica' 'virginica' 'versicolor' 'setosa'
##  'virginica' 'versicolor' 'versicolor' 'virginica' 'setosa' 'virginica'
##  'setosa' 'setosa']

Entrena el modelo y realiza la predicción sobre la tabla de testing, además muestra los principales índices de precisión para medir la calidad del modelo. Esto utilizando el método fit_predict_resultados().

resultados = analisis_Iris.fit_predict_resultados()
## 
## Matriz de Confusión:
## [[16  0  0]
##  [ 0 17  1]
##  [ 0  0 11]]
## 
## Precisión Global:
## 0.9777777777777777
## 
## Error Global:
## 0.022222222222222254
## 
## Precisión por categoría:
##    setosa  versicolor  virginica
## 0     1.0    0.944444        1.0

Predicción con selección de variables

# Usamos los parámetros por defecto
qda = QuadraticDiscriminantAnalysis()

analisis_Iris = Analisis_Predictivo(datos, predecir = "tipo", predictoras = ["p.ancho","p.largo"],
                                    modelo = qda, train_size = 0.7, random_state = 0)

#Podemos ver la tabla de training
analisis_Iris.X_train.head()
##      p.ancho  p.largo
## 60       1.0      3.5
## 116      1.8      5.5
## 144      2.5      5.7
## 119      1.5      5.0
## 108      1.8      5.8
#Entrenamos, predecimos y medimos la calidad del modelo generado
resultados = analisis_Iris.fit_predict_resultados()
## 
## Matriz de Confusión:
## [[16  0  0]
##  [ 0 18  0]
##  [ 0  0 11]]
## 
## Precisión Global:
## 1.0
## 
## Error Global:
## 0.0
## 
## Precisión por categoría:
##    setosa  versicolor  virginica
## 0     1.0         1.0        1.0

Ejemplo 2

Carga de datos

Se cargan los datos de Scoring de Crédito.

datos = pd.read_csv('../datos/MuestraCredito5000V2.csv', delimiter = ';', decimal = ".")
print(datos.shape)
## (5000, 6)
print(datos.head())
##    MontoCredito  IngresoNeto  ...  GradoAcademico BuenPagador
## 0         14327            1  ...       Bachiller          Si
## 1        111404            1  ...       Bachiller          Si
## 2         21128            1  ...       Bachiller          Si
## 3         15426            2  ...       Bachiller          Si
## 4         10351            1  ...       Bachiller          Si
## 
## [5 rows x 6 columns]
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 5000 entries, 0 to 4999
## Data columns (total 6 columns):
##  #   Column             Non-Null Count  Dtype 
## ---  ------             --------------  ----- 
##  0   MontoCredito       5000 non-null   int64 
##  1   IngresoNeto        5000 non-null   int64 
##  2   CoefCreditoAvaluo  5000 non-null   int64 
##  3   MontoCuota         5000 non-null   object
##  4   GradoAcademico     5000 non-null   object
##  5   BuenPagador        5000 non-null   object
## dtypes: int64(3), object(3)
## memory usage: 234.5+ KB
## None
Nota: Está tomando erroneamente los datos como numéricos, en este caso se deben convertir las variables categóricas porque en realidad estos numéros son códigos NO es que siempre se deban convertir las variables numéricas a categórica.
# Convierte las variables de object a categórica
datos['IngresoNeto'] = datos['IngresoNeto'].astype('category')
datos['CoefCreditoAvaluo'] = datos['CoefCreditoAvaluo'].astype('category')
datos['MontoCuota'] = datos['MontoCuota'].astype('category')
datos['GradoAcademico'] = datos['GradoAcademico'].astype('category')
# Recodifica las categorías usando números
datos["MontoCuota"] = datos["MontoCuota"].cat.codes
datos["GradoAcademico"] = datos["GradoAcademico"].cat.codes
# Convierte las variables de entero a categórica
datos['MontoCuota'] = datos['MontoCuota'].astype('category')
datos['GradoAcademico'] = datos['GradoAcademico'].astype('category')
print(datos.head())
##    MontoCredito IngresoNeto  ... GradoAcademico BuenPagador
## 0         14327           1  ...              0          Si
## 1        111404           1  ...              0          Si
## 2         21128           1  ...              0          Si
## 3         15426           2  ...              0          Si
## 4         10351           1  ...              0          Si
## 
## [5 rows x 6 columns]
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 5000 entries, 0 to 4999
## Data columns (total 6 columns):
##  #   Column             Non-Null Count  Dtype   
## ---  ------             --------------  -----   
##  0   MontoCredito       5000 non-null   int64   
##  1   IngresoNeto        5000 non-null   category
##  2   CoefCreditoAvaluo  5000 non-null   category
##  3   MontoCuota         5000 non-null   category
##  4   GradoAcademico     5000 non-null   category
##  5   BuenPagador        5000 non-null   object  
## dtypes: category(4), int64(1), object(1)
## memory usage: 98.6+ KB
## None

Poder Predictivo

Configuramos y creamos nuestras instancias.

qda = QuadraticDiscriminantAnalysis()
analisis_scoring = Analisis_Predictivo(datos, predecir = "BuenPagador", modelo = qda,
                                       train_size = 0.75, random_state = 0)

Balance de las clases en la variable a predecir - Problema desvalanceado.

analisis_scoring.distribucion_variable_predecir()
plt.show()

Poder predictivo.

for var in datos.columns[0:5]:
  if(datos[var].dtype in ['float64', 'int', 'float']):
    analisis_scoring.poder_predictivo_numerica(var)
    plt.show()
  else:
    analisis_scoring.poder_predictivo_categorica(var)
    plt.show()

Predicción

Entrenamos el modelo y medimos la calidad del mismo con la predicción generada con base a la tabla de testing.

resultados = analisis_scoring.fit_predict_resultados()
## 
## Matriz de Confusión:
## [[  28  138]
##  [  51 1033]]
## 
## Precisión Global:
## 0.8488
## 
## Error Global:
## 0.1512
## 
## Precisión por categoría:
##          No        Si
## 0  0.168675  0.952952

También podemos simplemente guardar los resultados y no imprimir en pantalla.

resultados = analisis_scoring.fit_predict_resultados(imprimir = False)
resultados
## {'Matriz de Confusión': array([[  28,  138],
##        [  51, 1033]]), 'Precisión Global': 0.8488, 'Error Global': 0.1512, 'Precisión por categoría':          No        Si
## 0  0.168675  0.952952}

Ejemplo 3

Carga de datos

Se cargan los datos de SAHeart.

datos = pd.read_csv('../datos/SAheart.csv',delimiter=';',decimal=".")
print(datos.shape)
## (462, 10)
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 462 entries, 0 to 461
## Data columns (total 10 columns):
##  #   Column     Non-Null Count  Dtype  
## ---  ------     --------------  -----  
##  0   sbp        462 non-null    int64  
##  1   tobacco    462 non-null    float64
##  2   ldl        462 non-null    float64
##  3   adiposity  462 non-null    float64
##  4   famhist    462 non-null    object 
##  5   typea      462 non-null    int64  
##  6   obesity    462 non-null    float64
##  7   alcohol    462 non-null    float64
##  8   age        462 non-null    int64  
##  9   chd        462 non-null    object 
## dtypes: float64(5), int64(3), object(2)
## memory usage: 36.2+ KB
## None
print(datos.head())
##    sbp  tobacco   ldl  adiposity  famhist  typea  obesity  alcohol  age chd
## 0  160    12.00  5.73      23.11  Present     49    25.30    97.20   52  Si
## 1  144     0.01  4.41      28.61   Absent     55    28.87     2.06   63  Si
## 2  118     0.08  3.48      32.28  Present     52    29.14     3.81   46  No
## 3  170     7.50  6.41      38.03  Present     51    31.99    24.26   58  Si
## 4  134    13.60  3.50      27.78  Present     60    25.99    57.34   49  Si
# Convierte las variables de object a categórica
datos['famhist'] = datos['famhist'].astype('category')
# Recodifica las categorías usando números
datos["famhist"] = datos["famhist"].cat.codes
# Convierte las variables de entero a categórica
datos['famhist'] = datos['famhist'].astype('category')
print(datos.info())
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 462 entries, 0 to 461
## Data columns (total 10 columns):
##  #   Column     Non-Null Count  Dtype   
## ---  ------     --------------  -----   
##  0   sbp        462 non-null    int64   
##  1   tobacco    462 non-null    float64 
##  2   ldl        462 non-null    float64 
##  3   adiposity  462 non-null    float64 
##  4   famhist    462 non-null    category
##  5   typea      462 non-null    int64   
##  6   obesity    462 non-null    float64 
##  7   alcohol    462 non-null    float64 
##  8   age        462 non-null    int64   
##  9   chd        462 non-null    object  
## dtypes: category(1), float64(5), int64(3), object(1)
## memory usage: 33.2+ KB
## None
datos.head()
##    sbp  tobacco   ldl  adiposity famhist  typea  obesity  alcohol  age chd
## 0  160    12.00  5.73      23.11       1     49    25.30    97.20   52  Si
## 1  144     0.01  4.41      28.61       0     55    28.87     2.06   63  Si
## 2  118     0.08  3.48      32.28       1     52    29.14     3.81   46  No
## 3  170     7.50  6.41      38.03       1     51    31.99    24.26   58  Si
## 4  134    13.60  3.50      27.78       1     60    25.99    57.34   49  Si

Poder Predictivo

Configuramos y creamos nuestras instancias.

qda = QuadraticDiscriminantAnalysis()
analisis_Sheart = Analisis_Predictivo(datos, predecir = "chd", modelo = qda,
                                      train_size = 0.8, random_state = 0)

Equilibrio de la variable a predecir.

analisis_Sheart.distribucion_variable_predecir()
plt.show()

Poder predictivo.

for var in datos.columns[0:9]:
  if(datos[var].dtype in ['float64', 'int', 'float']):
    analisis_Sheart.poder_predictivo_numerica(var)
    plt.show()
  else:
    analisis_Sheart.poder_predictivo_categorica(var)
    plt.show()

Predicción

Entrena, predice y mide la calidad.

resultados = analisis_Sheart.fit_predict_resultados()
## 
## Matriz de Confusión:
## [[52  9]
##  [16 16]]
## 
## Precisión Global:
## 0.7311827956989247
## 
## Error Global:
## 0.26881720430107525
## 
## Precisión por categoría:
##          No   Si
## 0  0.852459  0.5